package common;

import java.util.LinkedList;

public class DominoState {

    /**
     * Number of pieces of the complete order 6 domino set.
     */
    public static final int PIECE_SET_SIZE = 28;
    /**
     * Number of pieces received by each player in the beginning of the game.
     */
    public static final int PIECES_PER_PLAYER = 12;
    /**
     * The maximum value that each piece can have on one side.
     */
    public static final int DOMINO_ORDER = 6;
    /**
     * Array of all domino pieces.
     */
    public static Piece[] allPieces;

    /**
     * Inicialization of the allPieces array.
     */
    static {
        allPieces = new Piece[PIECE_SET_SIZE];

        int contador = 0;
        for (byte i = 0; i <= DOMINO_ORDER; i++) {
            for (byte j = i; j <= DOMINO_ORDER; j++) {
                allPieces[contador++] = new Piece(i, j);
            }
        }
    }

    /**
     * List of already played pieces.
     */
    protected LinkedList<Piece> playedPieces;
    /**
     * The outside value of the first piece in the playedPieces list.
     */
    protected byte leftValue;
    protected byte oldLeftValue;
    /**
     * The outside value of the last piece in the playedPieces list.
     */
    protected byte rightValue;
    protected byte oldRightValue;

    public DominoState() {
        playedPieces = new LinkedList<>();
        initialize();
    }

    public DominoState(DominoState ds) {
        this();
        for (Piece p : ds.playedPieces) {
            this.playedPieces.add(p);
        }
        this.leftValue = ds.leftValue;
        this.oldLeftValue = ds.oldLeftValue;
        this.rightValue = ds.rightValue;
        this.oldRightValue = ds.oldRightValue;
    }

    public void restart() {
        initialize();
    }

    /**
     * Places a piece in the given side of the list of already placed pieces.
     *
     * @param side the side of the list of already played pieces where the piece
     * must be placed.
     * @param piece the piece to be placed.
     * @return true if the piece can be placed (valid move) and false,
     * otherwise.
     */
    public boolean placePiece(Side side, Piece piece) {
        if (!isValidMove(side, piece)) {
            return false;
        }

        if (playedPieces.isEmpty()) {
            playedPieces.add(piece);
            oldLeftValue = leftValue;
            oldRightValue = rightValue;
            leftValue = piece.getValue1();
            rightValue = piece.getValue2();
        } else if (side == Side.LEFT) {
            byte outsideValue = piece.getOppositeValue(leftValue);
            oldLeftValue = leftValue;
            leftValue = outsideValue;
            playedPieces.addFirst(piece);
        } else {
            byte outsideValue = piece.getOppositeValue(rightValue);
            oldRightValue = rightValue;
            rightValue = outsideValue;
            playedPieces.addLast(piece);
        }

        return true;
    }

    /**
     * Returns true if the piece can be placed in the given side of the list of
     * already placed pieces and false, otherwise.
     *
     * @param side the side of the list of already played pieces where the piece
     * must be placed.
     * @param piece the piece to be placed.
     * @return true if the piece can be placed (valid move) and false,
     * otherwise.
     */
    public boolean isValidMove(Side side, Piece piece) {
        return playedPieces.isEmpty() || side == Side.LEFT && piece.hasValue(leftValue) || side == Side.RIGHT && piece.hasValue(rightValue);
    }

    /**
     * Returns a list with all the pieces in the allPieces array.
     *
     * @return list with all the pieces in the allPieces array.
     */
    public static LinkedList<Piece> getAllPiecesList() {
        LinkedList<Piece> allPiecesList = new LinkedList<>();
        for (int i = 0; i < DominoState.PIECE_SET_SIZE; i++) {
            allPiecesList.add(allPieces[i]);
        }
        return allPiecesList;
    }

    private void initialize() {
        playedPieces.clear();
    }

    @Override
    public String toString() {
        StringBuilder buffer = new StringBuilder();
        buffer.append('[');
        for (Piece piece : playedPieces) {
            buffer.append("" + piece.getValue1() + "|" + piece.getValue2() + "] ");
        }
        return buffer.toString();
    }

    public int getAllDots() {
        int soma = 0;
        for (Piece p : allPieces) {
            soma += p.getValuesSum();
        }
        return soma;
    }
}
